﻿using DependencyInjection.StaticAccessor;
using FreeSql;
using FreeSql.Internal;
using FreeSql.Internal.CommonProvider;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MySqlConnector;
using System;
using System.Data.Common;
using System.Reflection;

 namespace FreeSql
{
    public static class FreeSqlMySqlExtension
    {
        public static void AddSql(this IServiceCollection services, IConfigurationSection section)
        {

            var config = section.Get<DbConfig>() ?? new DbConfig();
            services.Configure<DbConfig>(section);
            DbConfig.DbBegDate = config.BegDate;
            IdHelper.SetIdGeneratorOptions(config.WorkerId, (byte)config.WorkerIdBitLength);
            //var logger = PinnedScope.ScopedServices?.GetRequiredService<ILogger>();


            IFreeSql fsql = new FreeSqlBuilder()
                .UseConnectionString(DataType.MySql, config.ConnectionString)
                 .UseNameConvert(NameConvertType.PascalCaseToUnderscoreWithLower)//oracle 全部转为大写
                .CreateDatabaseIfNotExistsMySql()
                .UseMonitorCommand(
                    cmd =>
                    {
                        cmd.CommandTimeout = 9999;
                        if (config.WatchCurd)
                        {
                            var p = "";
                            foreach (DbParameter item in cmd.Parameters)
                            {
                                if (p == "") p += "\r\nParameters：\r\n";
                                p += ($"ParameterName:{item.ParameterName},Value:{item.Value}\r\n");
                            }
                            Serilog.Log.Logger.Debug("\r\n*******begin================SQL================**********\r\n" + cmd.CommandText + p + "\r\n*******end================SQL================**********");
                        }
                    })
                .UseNoneCommandParameter(config.NoneCommandParameter)
                //.UseAutoSyncStructure(config.SyncStructure) //自动同步实体结构到数据库，只有CRUD时才会生成表
                .Build();

            fsql.UseJsonMap();

            //var selectProvider = fsql.Select<object>() as Select0Provider;
            //var serverTime = fsql.Select<object>().WithSql($"select {selectProvider._commonUtils.NowUtc} a").First(a => Convert.ToDateTime("a"));
            //var timeOffset = DateTime.UtcNow.Subtract(serverTime);

            fsql.Aop.AuditValue += (s, e) =>
            {

                DbHelper.AuditValue(e);
            };

            fsql.Aop.ConfigEntityProperty += (s, e) =>
            {
                DbHelper.ConfigEntityProperty(s, e);
            };
            fsql.GlobalFilter.Apply<IBaseSoftDelete>(nameof(IBaseSoftDelete), a => a.IsDeleted == false);




            services.AddSingleton<IFreeSql>(fsql);
            services.AddScoped<UnitOfWorkManager>();
            services.AddScoped(typeof(IRepositoryDefault<>), typeof(RepositoryDefault<>));
            services.AddScoped(typeof(IRepositoryBase<>), typeof(RepositoryBase<>));
            services.AddScoped(typeof(IRepositoryDefault<,>), typeof(RepositoryDefault<,>));
            services.AddScoped(typeof(IRepositoryBase<,>), typeof(RepositoryBase<,>));
            //services.AddScoped(typeof(IBaseRepository<>), typeof(GuidRepository<>));
            //services.AddScoped(typeof(BaseRepository<>), typeof(GuidRepository<>));
            //services.AddScoped(typeof(IBaseRepository<,>), typeof(DefaultRepository<,>));
            //services.AddScoped(typeof(BaseRepository<,>), typeof(DefaultRepository<,>));

        }

        #region MySql
        /// <summary>
        /// 创建数据库
        /// </summary>
        /// <param name="this"></param>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        public static FreeSqlBuilder CreateDatabaseIfNotExistsMySql(this FreeSqlBuilder @this, string connectionString = "")
        {
            if (connectionString == "")
            {
                connectionString = GetConnectionString(@this);
            }

            MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder(connectionString);

            string createDatabaseSql = $"USE mysql;CREATE DATABASE IF NOT EXISTS `{builder.Database}` CHARACTER SET '{builder.CharacterSet}' COLLATE 'utf8_general_ci'";

            using MySqlConnection cnn = new MySqlConnection($"Data Source={builder.Server};Port={builder.Port};User ID={builder.UserID};Password={builder.Password};Initial Catalog=mysql;Charset=utf8;SslMode=none;Max pool size=1");
            cnn.Open();
            using (MySqlCommand cmd = cnn.CreateCommand())
            {
                cmd.CommandText = createDatabaseSql;
                cmd.ExecuteNonQuery();
            }

            return @this;
        }


        public static FreeSqlBuilder DropDatabaseIfNotExists(this FreeSqlBuilder @this)
        {
            FieldInfo? dataTypeFieldInfo = @this.GetType().GetField("_dataType", BindingFlags.NonPublic | BindingFlags.Instance);

            if (dataTypeFieldInfo is null)
            {
                throw new ArgumentException("_dataType is null");
            }
            string connectionString = GetConnectionString(@this);
            /* DataType? dbType = (DataType?)dataTypeFieldInfo.GetValue(@this);
             if (DataType.MySql != dbType)
             {
                 throw new Exception("不是mysql数据库类型");
             }*/
            return @this.DropDatabaseIfExistsMySql(connectionString);
            //    Log.Error($"不支持创建数据库");
        }


        public static FreeSqlBuilder DropDatabaseIfExistsMySql(this FreeSqlBuilder @this, string connectionString = "")
        {
            if (connectionString == "")
            {
                connectionString = GetConnectionString(@this);
            }

            MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder(connectionString);

            string createDatabaseSql = $"USE mysql;DROP DATABASE IF EXISTS `{builder.Database}`";

            using MySqlConnection cnn = new MySqlConnection($"Data Source={builder.Server};Port={builder.Port};User ID={builder.UserID};Password={builder.Password};Initial Catalog=mysql;Charset=utf8;SslMode=none;Max pool size=1");
            cnn.Open();
            using (MySqlCommand cmd = cnn.CreateCommand())
            {
                cmd.CommandText = createDatabaseSql;
                cmd.ExecuteNonQuery();
            }

            return @this;
        }

        public static FreeSqlBuilder CreateDatabaseIfNotExists(this FreeSqlBuilder @this)
        {
            FieldInfo? dataTypeFieldInfo = @this.GetType().GetField("_dataType", BindingFlags.NonPublic | BindingFlags.Instance);

            if (dataTypeFieldInfo is null)
            {
                throw new ArgumentException("_dataType is null");
            }

            string connectionString = GetConnectionString(@this);
            /*  DataType dbType = (DataType)dataTypeFieldInfo.GetValue(@this);
              if (dbType != DataType.MySql)
              {
                  throw new Exception("不是mysql数据库类型");
              }*/
            return @this.CreateDatabaseIfNotExistsMySql(connectionString);
            //    Log.Error($"不支持创建数据库");
        }
        private static string GetConnectionString(FreeSqlBuilder @this)
        {
            Type type = @this.GetType();
            FieldInfo? fieldInfo = type.GetField("_masterConnectionString", BindingFlags.NonPublic | BindingFlags.Instance);
            if (fieldInfo is null)
            {
                throw new ArgumentException("_masterConnectionString is null");
            }
            return fieldInfo.GetValue(@this)?.ToString() ?? "";
        }


        #endregion

    }
}
